package com.structurizr.view;

import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.*;

public class ElementStyleTests {

    @Test
    void setOpacity() {
        ElementStyle style = new ElementStyle();
        assertNull(style.getOpacity());

        style.setOpacity(-1);
        assertEquals(0, style.getOpacity().intValue());

        style.setOpacity(0);
        assertEquals(0, style.getOpacity().intValue());

        style.setOpacity(50);
        assertEquals(50, style.getOpacity().intValue());

        style.setOpacity(100);
        assertEquals(100, style.getOpacity().intValue());

        style.setOpacity(101);
        assertEquals(100, style.getOpacity().intValue());
    }

    @Test
    void opacity() {
        ElementStyle style = new ElementStyle();
        assertNull(style.getOpacity());

        style.opacity(-1);
        assertEquals(0, style.getOpacity().intValue());

        style.opacity(0);
        assertEquals(0, style.getOpacity().intValue());

        style.opacity(50);
        assertEquals(50, style.getOpacity().intValue());

        style.opacity(100);
        assertEquals(100, style.getOpacity().intValue());

        style.opacity(101);
        assertEquals(100, style.getOpacity().intValue());
    }

    @Test
    void setColor_SetsTheColorProperty_WhenAValidHexColorCodeIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.setColor("#ffffff");
        assertEquals("#ffffff", style.getColor());

        style.setColor("#FFFFFF");
        assertEquals("#ffffff", style.getColor());

        style.setColor("#123456");
        assertEquals("#123456", style.getColor());
    }

    @Test
    void color_SetsTheColorProperty_WhenAValidHexColorCodeIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.color("#ffffff");
        assertEquals("#ffffff", style.getColor());

        style.color("#FFFFFF");
        assertEquals("#ffffff", style.getColor());

        style.color("#123456");
        assertEquals("#123456", style.getColor());
    }

    @Test
    void setColor_SetsTheColorProperty_WhenAValidColorNameIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.setColor("yellow");
        assertEquals("#ffff00", style.getColor());
    }

    @Test
    void color_SetsTheColorProperty_WhenAValidColorNameIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.color("yellow");
        assertEquals("#ffff00", style.getColor());
    }

    @Test
    void setColor_ThrowsAnException_WhenAnInvalidHexColorCodeIsSpecified() {
        assertThrows(IllegalArgumentException.class, () -> {
            ElementStyle style = new ElementStyle();
            style.setColor("hello");
        });
    }

    @Test
    void color_ThrowsAnException_WhenAnInvalidHexColorCodeIsSpecified() {
        assertThrows(IllegalArgumentException.class, () -> {
            ElementStyle style = new ElementStyle();
            style.color("hello");
        });
    }

    @Test
    void setBackground_SetsTheBackgroundProperty_WhenAValidHexColorCodeIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.setBackground("#ffffff");
        assertEquals("#ffffff", style.getBackground());

        style.setBackground("#FFFFFF");
        assertEquals("#ffffff", style.getBackground());

        style.setBackground("#123456");
        assertEquals("#123456", style.getBackground());
    }

    @Test
    void background_SetsTheBackgroundProperty_WhenAValidHexColorCodeIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.background("#ffffff");
        assertEquals("#ffffff", style.getBackground());

        style.background("#FFFFFF");
        assertEquals("#ffffff", style.getBackground());

        style.background("#123456");
        assertEquals("#123456", style.getBackground());
    }

    @Test
    void setBackground_SetsTheBackgroundProperty_WhenAValidColorNameIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.setBackground("yellow");
        assertEquals("#ffff00", style.getBackground());
    }

    @Test
    void background_SetsTheBackgroundProperty_WhenAValidColorNameIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.background("yellow");
        assertEquals("#ffff00", style.getBackground());
    }

    @Test
    void setBackground_ThrowsAnException_WhenAnInvalidHexColorCodeIsSpecified() {
        assertThrows(IllegalArgumentException.class, () -> {
            ElementStyle style = new ElementStyle();
            style.setBackground("hello");
        });
    }

    @Test
    void background_ThrowsAnException_WhenAnInvalidHexColorCodeIsSpecified() {
        assertThrows(IllegalArgumentException.class, () -> {
            ElementStyle style = new ElementStyle();
            style.background("hello");
        });
    }

    @Test
    void setIcon_WithAUrl() {
        ElementStyle style = new ElementStyle();
        style.setIcon("https://structurizr.com/static/img/structurizr-logo.png");
        assertEquals("https://structurizr.com/static/img/structurizr-logo.png", style.getIcon());
    }

    @Test
    void setIcon_WithAUrlThatHasATrailingSpaceCharacter() {
        ElementStyle style = new ElementStyle();
        style.setIcon("https://structurizr.com/static/img/structurizr-logo.png ");
        assertEquals("https://structurizr.com/static/img/structurizr-logo.png", style.getIcon());
    }

    @Test
    void setIcon_WithADataUri() {
        ElementStyle style = new ElementStyle();
        style.setIcon("");
        assertEquals("", style.getIcon());
    }

    @Test
    void setIcon_ThrowsAnIllegalArgumentException_WhenAnInvalidUrlIsSpecified() {
        assertThrows(IllegalArgumentException.class, () -> {
            ElementStyle style = new ElementStyle();
            style.setIcon("htt://blah");
        });
    }

    @Test
    void setIcon_DoesNothing_WhenANullUrlIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.setIcon(null);
        assertNull(style.getIcon());
    }

    @Test
    void setIcon_DoesNothing_WhenAnEmptyUrlIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.setIcon(" ");
        assertNull(style.getIcon());
    }

    @Test
    void setStroke_SetsTheStrokeProperty_WhenAValidHexColorCodeIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.setStroke("#ffffff");
        assertEquals("#ffffff", style.getStroke());

        style.setStroke("#FFFFFF");
        assertEquals("#ffffff", style.getStroke());

        style.setStroke("#123456");
        assertEquals("#123456", style.getStroke());
    }

    @Test
    void Stroke_SetsTheStrokeProperty_WhenAValidHexColorCodeIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.stroke("#ffffff");
        assertEquals("#ffffff", style.getStroke());

        style.stroke("#FFFFFF");
        assertEquals("#ffffff", style.getStroke());

        style.stroke("#123456");
        assertEquals("#123456", style.getStroke());
    }

    @Test
    void setStroke_SetsTheStrokeProperty_WhenAValidColorNameIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.setStroke("yellow");
        assertEquals("#ffff00", style.getStroke());
    }

    @Test
    void Stroke_SetsTheStrokeProperty_WhenAValidColorNameIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.stroke("yellow");
        assertEquals("#ffff00", style.getStroke());
    }

    @Test
    void setStroke_ThrowsAnException_WhenAnInvalidHexColorCodeIsSpecified() {
        assertThrows(IllegalArgumentException.class, () -> {
            ElementStyle style = new ElementStyle();
            style.setStroke("hello");
        });
    }

    @Test
    void Stroke_ThrowsAnException_WhenAnInvalidHexColorCodeIsSpecified() {
        assertThrows(IllegalArgumentException.class, () -> {
            ElementStyle style = new ElementStyle();
            style.stroke("hello");
        });
    }

    @Test
    void getProperties_ReturnsAnEmptyList_WhenNoPropertiesHaveBeenAdded() {
        ElementStyle style = new ElementStyle();
        assertEquals(0, style.getProperties().size());
    }

    @Test
    void addProperty_ThrowsAnException_WhenTheNameIsNull() {
        try {
            ElementStyle style = new ElementStyle();
            style.addProperty(null, "value");
            fail();
        } catch (IllegalArgumentException e) {
            assertEquals("A property name must be specified.", e.getMessage());
        }
    }

    @Test
    void addProperty_ThrowsAnException_WhenTheNameIsEmpty() {
        try {
            ElementStyle style = new ElementStyle();
            style.addProperty(" ", "value");
            fail();
        } catch (IllegalArgumentException e) {
            assertEquals("A property name must be specified.", e.getMessage());
        }
    }

    @Test
    void addProperty_ThrowsAnException_WhenTheValueIsNull() {
        try {
            ElementStyle style = new ElementStyle();
            style.addProperty("name", null);
            fail();
        } catch (IllegalArgumentException e) {
            assertEquals("A property value must be specified.", e.getMessage());
        }
    }

    @Test
    void addProperty_ThrowsAnException_WhenTheValueIsEmpty() {
        try {
            ElementStyle style = new ElementStyle();
            style.addProperty("name", " ");
            fail();
        } catch (IllegalArgumentException e) {
            assertEquals("A property value must be specified.", e.getMessage());
        }
    }

    @Test
    void addProperty_AddsTheProperty_WhenANameAndValueAreSpecified() {
        ElementStyle style = new ElementStyle();
        style.addProperty("name", "value");
        assertEquals("value", style.getProperties().get("name"));
    }

    @Test
    void setProperties_DoesNothing_WhenNullIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.setProperties(null);
        assertEquals(0, style.getProperties().size());
    }

    @Test
    void setProperties_SetsTheProperties_WhenANonEmptyMapIsSpecified() {
        ElementStyle style = new ElementStyle();
        Map<String, String> properties = new HashMap<>();
        properties.put("name", "value");
        style.setProperties(properties);
        assertEquals(1, style.getProperties().size());
        assertEquals("value", style.getProperties().get("name"));
    }

    @Test
    void setStrokeWidth_WhenNullIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.setStrokeWidth(10);
        style.setStrokeWidth(null);
        assertNull(style.getStrokeWidth());
    }

    @Test
    void setStrokeWidth_WhenANegativeIntegerIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.setStrokeWidth(-1);
        assertEquals(1, style.getStrokeWidth());
    }

    @Test
    void setStrokeWidth_WhenZeroIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.setStrokeWidth(0);
        assertEquals(1, style.getStrokeWidth());
    }

    @Test
    void setStrokeWidth_WhenAPositiveIntegerIsSpecified() {
        ElementStyle style = new ElementStyle();
        style.setStrokeWidth(10);
        assertEquals(10, style.getStrokeWidth());
    }

    @Test
    void setStrokeWidth_WhenAPositiveIntegerOver10IsSpecified() {
        ElementStyle style = new ElementStyle();
        style.setStrokeWidth(20);
        assertEquals(10, style.getStrokeWidth());
    }

}